﻿// <copyright file="DocumentEntityFields.cs" company="Recipe Database">
//     Copyright (c) Recipe Database. All rights reserved.
// </copyright>
// <author>Bjarke Meier</author>
//-----------------------------------------------------------------------

namespace Core.Rules
{
  using System;
  using System.Globalization;
  using System.IO;
  using System.Linq;
  using System.Xml.Linq;
  using Microsoft.FxCop.Sdk;

  /// <summary>
  /// Code analysis rule requiring all entity fields are documented.
  /// </summary>
  internal sealed class DocumentEntityFields : BaseRule
  {
    /// <summary>
    /// Initializes a new instance of the DocumentEntityFields class.
    /// </summary>
    public DocumentEntityFields()
      : base(typeof(DocumentEntityFields).Name)
    {
    }

    /// <summary>
    /// This method should never be called directly but only through the code analysis tool.
    /// TODO: The required length of documentationen stated in the resolution string isn't implemented
    /// </summary>
    /// <param name="resource">The resource currently being visited.</param>
    /// <returns>The problem collection.</returns>
    public override ProblemCollection Check(Resource resource)
    {
      const string Xmlns = "http://schemas.microsoft.com/ado/2008/09/edm";
      
      // TODO: How do we generally handle the culture problem?
      Func<string, string> xname = name => string.Format(CultureInfo.InvariantCulture, "{{{0}}}{1}", Xmlns, name);
      
      // TODO: We don't want ".csdl" as a resource, but can we avoid it as a string?
      if (resource.Name.EndsWith(".csdl", StringComparison.OrdinalIgnoreCase))
      {
        using (var stream = new MemoryStream(resource.Data))
        {
          var xml = XDocument.Load(stream);
         
          // TODO: Can we avoid the const strings in the query?
          var query = from p in xml.Descendants(xname("EntityType")).Descendants(xname("Property"))
                      where p.Descendants(xname("Documentation")).Count() == 0
                      select p;
          foreach (var property in query)
          {
            if (property.Parent == null)
            {
              // TODO: How do we generally handle the culture problem?
              throw new RulesException(string.Format(CultureInfo.CurrentCulture, DocumententityFieldsResources.The_parent_property_of_the_XElement_property_is_null, property.Name));
            }

// ReSharper disable PossibleNullReferenceException
            // TODO: Is it okay to disable R# warnings because we know that the "Name" properties always exists.
            //       Or do we have to check for nulls?
            var resolution = GetResolution(property.Parent.Attribute("Name").Value, property.Attribute("Name").Value);

// ReSharper restore PossibleNullReferenceException
            Problems.Add(new Problem(resolution));
          }
        }
      }

      return Problems;
    }
  }
}